package ac.github.oa.listener

import ac.github.oa.OriginAttribute
import ac.github.oa.api.Debug
import ac.github.oa.api.OriginAttributeAPI
import ac.github.oa.api.event.entity.EntityDamageEvent
import ac.github.oa.api.event.entity.EntityDeathEvent
import ac.github.oa.api.event.entity.ProxyDamageEvent
import ac.github.oa.api.event.render.AttributeRenderStringEvent
import ac.github.oa.internal.base.enums.PriorityEnum
import ac.github.oa.util.ArrayUtils
import io.lumine.mythic.bukkit.events.MythicMobDeathEvent
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobSpawnEvent
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.entity.EntityPickupItemEvent
import org.bukkit.event.entity.EntityShootBowEvent
import org.bukkit.event.entity.ItemMergeEvent
import org.bukkit.event.entity.ItemSpawnEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.player.PlayerDropItemEvent
import org.bukkit.event.player.PlayerItemHeldEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.metadata.FixedMetadataValue
import taboolib.common.platform.event.EventPriority
import taboolib.common.platform.event.OptionalEvent
import taboolib.common.platform.event.SubscribeEvent
import taboolib.platform.BukkitPlugin
import taboolib.platform.util.setMeta
import taboolib.type.BukkitEquipment

object OnListener {

    val damageCauses: List<String>
        get() = OriginAttribute.config.getStringList("options.damage-cause")


    @SubscribeEvent
    fun e(e: ProxyDamageEvent) {

        val context = e.createDamageContext()

        if (EntityDamageEvent(context, PriorityEnum.PRE).call()) {
            OriginAttributeAPI.callDamage(context)

            // POST CALL 战斗后不允许取消事件
            if (EntityDamageEvent(context, PriorityEnum.POST).call()) {
                e.damage = context.totalDamage.coerceAtLeast(0.0)
                Debug.log("DamageByEntity info:")
                context.getDamageSources().forEachIndexed { index, source ->
                    Debug.log("$index.${source.any} = ${source.value}")
                }

            }
        } else {
            e.isCancelled = true
        }

    }


    @SubscribeEvent(ignoreCancelled = true, priority = EventPriority.MONITOR)
    fun e(e: EntityDamageByEntityEvent) {
        if (e.cause.name in damageCauses || e.entity::class.java.simpleName != "PlayerNPC") {
            val proxyEvent = ProxyDamageEvent(e)
            if (proxyEvent.call()) {
                e.damage = proxyEvent.damage.coerceAtLeast(0.0)
            } else {
                e.isCancelled = true
            }
        }

    }

    @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true)
    fun e(event: EntityShootBowEvent) {
        val entity = event.projectile
        entity.setMeta("attributeData", OriginAttributeAPI.getAttributeData(event.entity))
        entity.setMeta("force", event.force)
        // 附着弓实体
        if (event.bow != null) {
            entity.setMeta("bow", event.bow!!)
        }
    }

    @SubscribeEvent
    fun e(event: ItemSpawnEvent) {
        if (event.isCancelled || event.entity.isCustomNameVisible) return
        val item = event.entity
        val itemStack = item.itemStack
        if (!event.isCancelled && itemStack.hasItemMeta() && itemStack.itemMeta!!.hasDisplayName()) {
            item.isCustomNameVisible = true
            if (itemStack.amount > 1) {
                item.customName = itemStack.itemMeta!!.displayName + " §b*" + itemStack.amount
            } else {
                item.customName = itemStack.itemMeta!!.displayName
            }
        }
    }

    @SubscribeEvent
    fun e(event: ItemMergeEvent) {
        if (event.isCancelled) return
        val item = event.target
        val oldItem = event.entity
        if (item.isCustomNameVisible) {
            item.customName =
                item.itemStack.itemMeta!!.displayName + " §b*" + (item.itemStack.amount + oldItem.itemStack.amount)
        }
    }

    @SubscribeEvent
    fun e(e: AttributeRenderStringEvent) {

        e.list.forEachIndexed { index, s ->
            var string = s
            val matchResult = OriginAttribute.numberRegex.find(s)
            matchResult?.apply {
                this.groupValues.forEach {
                    string =
                        s.replace(it, it.replace(OriginAttribute.config.getString("options.operator-add", "+")!!, "+"))
                    string =
                        s.replace(it, it.replace(OriginAttribute.config.getString("options.operator-take", "-")!!, "+"))
                }
            }
            e.list[index] = string
        }
    }


    @SubscribeEvent
    fun e(e: PlayerJoinEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent
    fun e(e: EntityPickupItemEvent) {
        asyncUpdate(e.entity)
    }

    @SubscribeEvent
    fun e(e: PlayerDropItemEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent
    fun e(e: PlayerItemHeldEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent
    fun e(e: InventoryCloseEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent(bind = "io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobSpawnEvent")
    fun handleMythicSpawn(ope: OptionalEvent) {
        val event = ope.get<MythicMobSpawnEvent>()
        val entity: Entity = event.entity

        if (entity is LivingEntity) {
            asyncMythicMob(
                entity,
                ArrayUtils.read(entity, event.mobType.config.getStringList("Attributes"), event.mobLevel),
                15
            )
        }
    }

    @SubscribeEvent(bind = "io.lumine.mythic.bukkit.events.MythicMobSpawnEvent")
    fun handleMythic5Spawn(ope: OptionalEvent) {
        val event = ope.get<io.lumine.mythic.bukkit.events.MythicMobSpawnEvent>()
        val entity: Entity = event.entity

        if (entity is LivingEntity) {
            asyncMythicMob(
                entity,
                ArrayUtils.read(entity, event.mobType.config.getStringList("Attributes"), event.mobLevel),
                15
            )
        }
    }

    fun asyncMythicMob(entity: LivingEntity, attributes: List<String>, delay: Long) {
        OriginAttributeAPI.async(delay = delay) {
            OriginAttributeAPI.loadEntityEquipment(entity).merge(
                OriginAttributeAPI.loadList(attributes)
            )
            OriginAttributeAPI.callUpdate(entity)
        }
    }

    @SubscribeEvent(bind = "io.lumine.xikage.mythicmobs.api.bukkit.events.EntityDeathEvent")
    fun handleMythicDeath(ope: OptionalEvent) {
        val event = ope.get<EntityDeathEvent>()
        val entity: Entity = event.entity
        if (entity is LivingEntity) {
            OriginAttributeAPI.remove(entity.uniqueId)
        }
    }

    @SubscribeEvent(bind = "io.lumine.mythic.bukkit.events.MythicMobDeathEvent")
    fun handleMythic5Death(ope: OptionalEvent) {
        val event = ope.get<MythicMobDeathEvent>()
        val entity: Entity = event.entity
        if (entity is LivingEntity) {
            OriginAttributeAPI.remove(entity.uniqueId)
        }
    }

    fun asyncUpdate(entity: LivingEntity, delay: Long = 0) {
        OriginAttributeAPI.async(delay = delay) {
            OriginAttributeAPI.loadEntityEquipment(entity)
            OriginAttributeAPI.callUpdate(entity)
        }
    }
}
